#include "app_buffer.h"
#include <stdlib.h>
#include <string.h>
#include <log/log.h>
static SubBuffer *app_buffer_subBuffer(int total_size)
{
    /*先申请一块内存装载小缓冲区的各个属性*/
    SubBuffer *sub_buffer = (SubBuffer *)malloc(sizeof(SubBuffer));
    /*再申请一块内存装载数据*/
    sub_buffer->ptr = malloc(total_size);
    sub_buffer->total_size = total_size;
    sub_buffer->len = 0;
    return sub_buffer;
}

static int swap_subbuffer(Buffer *buffer)
{
    log_debug("加写锁,开始切换缓冲区");
    /*加写锁，防止有线程在写缓冲区时，发生切换缓冲区的操作，切换和写不能同时进行*/
    pthread_mutex_lock(&(buffer->write_lock));
    int tmp = buffer->read_index;
    buffer->read_index = buffer->wirte_index;
    buffer->wirte_index = tmp;
    /*解写锁*/
    pthread_mutex_unlock(&(buffer->write_lock));
    log_debug("解开写锁,切换缓冲区完成");
    return 0;
}

/**
 * @brief 初始化缓冲区
 *
 * @param total_size 小缓冲区的大小
 */
Buffer *app_buffer_Init(int total_size)
{
    /*初始化大缓冲区*/
    Buffer *buffer = (Buffer *)malloc(sizeof(Buffer));
    /*初始化两个小缓冲区*/
    buffer->sub_buffers[0] = app_buffer_subBuffer(total_size);
    buffer->sub_buffers[1] = app_buffer_subBuffer(total_size);

    /*给大缓冲区添加属性*/
    buffer->wirte_index = 0;
    buffer->read_index = 1;

    pthread_mutex_init(&buffer->write_lock, NULL);
    pthread_mutex_init(&buffer->read_lock, NULL);

    return buffer;
}

/**
 * @brief 释放缓冲区
 *
 * @param arg
 */
void app_buffer_Free(Buffer *buffer)
{
    /*先释放小缓冲区的数据内存区域*/
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[1]->ptr);

    /*释放小缓冲区*/
    free(buffer->sub_buffers[0]);
    free(buffer->sub_buffers[1]);

    free(buffer);
}

/**
 * @brief 向缓冲区中写入数据
 *
 * @param buffer 待写入缓冲区
 * @param data 代写入的数据
 * @param len 数据长度
 * @return int 0：写入成功，-1：写入失败
 */
int app_buffer_writeBuffer(Buffer *buffer, char *data, int len)
{
    /*如果写入的数据长度大于255,则写入失败，因为后面我们只用了一个字节存储数据的长度*/
    if (len >= 255)
    {
        log_error("写入失败，数据长度超过255");
        return -1;
    }
    /*加写锁*/
    pthread_mutex_lock(&(buffer->write_lock));
    log_debug("加写锁，开始写入缓冲区,%.*s", len, data);
    /*获取写缓冲区*/
    SubBuffer *w_buffer = buffer->sub_buffers[buffer->wirte_index];
    /*如果待写入的数据长度大于缓冲区剩余长度，写入失败*/
    if (len > w_buffer->total_size - w_buffer->len - 1)
    {
        log_error("空间不足，写入失败");
        pthread_mutex_unlock(&(buffer->write_lock));
        return -1;
    }
    /*先写入数据的长度*/
    w_buffer->ptr[w_buffer->len] = len;
    /*写入数据*/
    memcpy(w_buffer->ptr + w_buffer->len + 1, data, len);
    /*更新数据长度*/
    w_buffer->len += len + 1;
    /*释放写锁*/
    pthread_mutex_unlock(&(buffer->write_lock));
    log_debug("解开写锁，写入完成-----");
    return 0;
}

/**
 * @brief 从缓冲区中读出数据
 *
 * @param buffer 待读取的缓冲区
 * @param data_buf 数据缓冲区
 * @param len 缓冲区长度
 * @return int 读取到的数据长度，-1：读取失败
 */
int app_buffer_readBuffer(Buffer *buffer, char *data_buf, int buf_size)
{
    log_debug("加读锁，开始读取缓冲区");
    /*加读锁*/
    pthread_mutex_lock(&(buffer->read_lock));
    /*获取读缓冲区*/
    SubBuffer *r_buffer = buffer->sub_buffers[buffer->read_index];
    /*如果读缓冲区为空，需要切换另外一个缓冲区*/
    if (r_buffer->len == 0)
    {
        log_debug("读的缓冲区为空，切换缓冲区");
        swap_subbuffer(buffer);
        /*再次获取读缓冲区*/
        r_buffer = buffer->sub_buffers[buffer->read_index];
        /*如果切换后缓冲区还是为空，那么说明还没有写入数据，直接退出*/
        if (r_buffer->len == 0)
        {
            log_error("缓冲区为空！");
            pthread_mutex_unlock(&(buffer->read_lock));
            return -1;
        }
    }

    /*先读取数据长度*/
    int data_len = r_buffer->ptr[0];
    log_debug("数据长度：%d",data_len);
    /*如果data_buf的长度小于要读出的数据的长度，则读取失败*/
    if (buf_size < data_len)
    {
        log_error("buf_size<data_len,读取失败");
        pthread_mutex_unlock(&(buffer->read_lock));
        return -1;
    }

    // memset(data_buf, 0, buf_size);
    memcpy(data_buf, r_buffer->ptr + 1, data_len);
    /*把后面的数据向前移动到缓冲区首部位置*/
    memmove(r_buffer->ptr, r_buffer->ptr + data_len + 1, r_buffer->len - data_len - 1);
    /*更新缓冲区数据长度*/
    //log_debug("更新前读缓冲区的数据长度：%d",r_buffer->len);
    r_buffer->len -= (data_len + 1);
    //log_debug("更新后读缓冲区的数据长度：%d",r_buffer->len);
    /*读取结束后，如果读缓冲区没有数据，切换缓冲区*/
    log_debug("获取到缓冲区数据:%.*s", data_len, data_buf);
    if (r_buffer->len == 0)
    {
        log_debug("因为读取结束后，如果读缓冲区没有数据，切换缓冲区");
        swap_subbuffer(buffer);
    }
    /*释放读锁*/
    pthread_mutex_unlock(&(buffer->read_lock));
    log_debug("解开读锁");
    return data_len;
}